package regions;

import java.util.LinkedList;

import base.Tower;
import base.Evaluation;

//Class representing a region of towers that can be 
public class Region {
	
	//Type of the Region  
	//public int type;
	
	public LinkedList<Tower> towers;
	
	public int gain;
	
	public int moves;
	
	public int getRating()
	{
		return gain/moves;
	}
	
	//range of values in the region
	public int lowerBound;
	
	public int upperBound;
	
	public int goalValue;
	
	public Tower midElement;
	
	public Region(Tower towerFirst, Tower towerSecond)
	{
		//type = 2;
		
		towers = new LinkedList<Tower>();
		towers.add(towerFirst);
		towers.add(towerSecond);
		
		this.gain = towerFirst.rocks + towerSecond.rocks;
		
		this.goalValue = (towerFirst.rocks + towerSecond.rocks)/2;
		
		this.moves = Math.abs(towerFirst.rocks - towerSecond.rocks);
		
		this.lowerBound = Math.min(towerFirst.rocks, towerSecond.rocks);
		
		this.upperBound= Math.max(towerFirst.rocks, towerSecond.rocks);
		
	}
	
	public Evaluation costToAddTower(Tower regionTower, Tower tower)
	{
		if (midElement != null)
		{
			if (midElement != regionTower)
			{
				return null;
			}
		}

		if (regionTower.rocks == this.lowerBound)
		{
			if (tower.rocks < this.lowerBound)
				return null;
		}
		if (regionTower.rocks == this.upperBound)
		{
			if (tower.rocks > this.upperBound)
				return null;
		}
		
		return createEvaluation(tower);
	
	}
	
	//Method for creating Evaluation if a tower is added to the region
	private Evaluation createEvaluation(Tower tower) {
		
		int goalVal = this.getGoalValue(tower.rocks);
		
		int newMoves = Math.abs(tower.rocks - this.goalValue);
		
		if (goalVal!=this.goalValue)
		{
			newMoves = 0;
			
			for(Tower tow: this.towers)
			{
				newMoves+=Math.abs(tow.rocks - goalVal);
			}
			newMoves+=Math.abs(tower.rocks - goalVal);
		}
		
		//Need only the difference
		newMoves = newMoves -  this.moves;
		
		return new Evaluation(newMoves, tower.rocks);
	}

	//Adding a new Tower to a region
	public void addToRegion(Tower towerFirst, Tower tower, Evaluation cost) {
		// TODO Auto-generated method stub
		if (this.midElement != null && this.midElement!=towerFirst)
		{
			System.err.println("Invalid insertion into a regin");
		}
		
		this.midElement = towerFirst;
		
		this.moves = cost.moves;
		
		this.gain = this.gain + cost.gain;

		this.goalValue = this.getGoalValue(tower.rocks);
		
		this.towers.addLast(tower);
		
		if (tower.rocks < this.lowerBound)
		{
			this.lowerBound = tower.rocks;

		}
		
		if (tower.rocks > this.upperBound)
		{
			this.upperBound = tower.rocks;
		}
		
		tower.region = this;
	}

	//Getting the Goal value if we add a new tower with inputRocks rocks
	private int getGoalValue(int inputRocks) {
		
		int middle = 0;
		
		for(Tower tow: this.towers)
		{
			middle += tow.rocks;
		}
		
		middle += inputRocks;
		
		middle = middle/(this.towers.size()+1);
		
		int goal = 0;
		
		for(Tower tow:this.towers)
		{
			if (Math.abs(tow.rocks - middle) < (middle - goal))
			{
				goal = tow.rocks;
			}
		}
		
		if (Math.abs(inputRocks - middle) < (middle - goal))
		{
			goal = inputRocks;
		}
		
		return goal;
	}
	
	//Try to remove a tower from the region and see what the gainloss is going to be(Non zero is the region is broken)
	public int tryRemove(Tower towerFirst) {
		
		int gainloss = 0;
		
		if (this.midElement == null || this.midElement.equals(towerFirst))
		{
			for(Tower tow:this.towers )
			{
				if(!tow.equals(towers))
				{
					gainloss += tow.rocks;
				}
			}
		}
		
		return gainloss;
		
	}
	
	public String toString()
	{
		StringBuilder result = new StringBuilder();
		
		if (this.midElement!=null)
		result.append("Region: center(").append(this.midElement.x).append(",").append(this.midElement.y).append(") -> ");
		
		for(Tower tow:this.towers)
		{
			result.append(tow.rocks).append(" ");
		}
		
		return result.toString();
	}

}
